import {InvokeCodeService} from './invoke-code-service';
import {InvokeUtils} from '../../utils/invoke-utils';
import {InvokeDataRest} from '../../entity/invoke-data-rest';

export class JavaInvokeCodeService implements InvokeCodeService {
    getCode(data: InvokeDataRest): string {
        const code = [];
        code.push('```java\n');
        code.push('/** \n');
        code.push(' * 本方法使用了okhttp包，项目地址：https://github.com/square/okhttp/\n');
        code.push(' * implementation("com.squareup.okhttp3:okhttp:3.12.0")\n');
        code.push(' * import okhttp3.*;\n');
        code.push(' */\n');
        code.push('OkHttpClient client = new OkHttpClient();\n');

        let hasPostBody = false;
        if (data.method === 'POST' && data.requestBody) {
            if (data.requestBody.rawDataType === 'raw' && data.requestBody.rawData) {
                this.renderRawCommend(code, data);
            } else {
                if (data.requestBody.rawDataType === 'x-www-form-urlencoded') {
                    this.renderFormUrlEncodedCommend(code, data);
                } else if (data.requestBody.rawDataType === 'form-data') {
                    this.renderFormDataCommend(code, data);
                }
            }
            hasPostBody = true;
        }

        code.push('Request request = new Request.Builder()\n');
        code.push('\t.url("');
        code.push(InvokeUtils.getUrl(data));
        code.push('")\n');

        if (hasPostBody) {
            code.push('\t.post(body)\n');
        }

        const headerKeys = new Set();
        if (data.headers) {
            data.headers.forEach(header => {
                if (header.key.length === 0) {
                    return;
                }
                if (headerKeys.has(header.key)) {
                    return;
                }
                headerKeys.add(header.key);
                this.addHeader(code, header);
            });
        }
        if (data.env.headers) {
            data.env.headers.forEach(header => {
                if (header.key.length === 0 || headerKeys.has(header.key)) {
                    return;
                }
                headerKeys.add(header.key);
                this.addHeader(code, header);
            });
        }

        code.push('\t.build();\n');
        code.push('try {\n');
        code.push('\tResponse response = client.newCall(request).execute();\n');
        code.push('} catch (IOException e) {\n');
        code.push('\te.printStackTrace();\n');
        code.push('}\n');
        code.push('```');

        return code.join('');
    }

    private addHeader(code: string[], header) {
        code.push('\t.addHeader("');
        code.push(header.key);
        code.push('", "');
        code.push(header.value);
        code.push('")\n');
    }

    private renderFormDataCommend(code: string[], data: InvokeDataRest) {
        if (!data.requestBody.formData) {
            return;
        }

        code.push('RequestBody body = new MultipartBody.Builder()\n');
        code.push('\t.setType(MultipartBody.FORM)\n');
        let hasParam = false;
        data.requestBody.formData.forEach(item => {
            if (item.key) {
                code.push(`\t.addFormDataPart("${item.key}", "${item.value}")\n`);
                hasParam = true;
            }
        });
        if (hasParam) {
            code.push('\t.build();\n');
        }
    }

    private renderFormUrlEncodedCommend(code: string[], data: InvokeDataRest) {
        const urlParams = InvokeUtils.joinUrlEncodedParams(data.requestBody.formData);
        if (urlParams) {
            code.push(`MediaType mediaType = MediaType.parse("${data.getContentType()}");\n`);
            code.push(`RequestBody body = RequestBody.create(mediaType, "`);
            code.push(urlParams);
            code.push('");\n');
        }
    }

    private renderRawCommend(code: string[], data: InvokeDataRest) {
        code.push(`MediaType mediaType = MediaType.parse("${data.getContentType()}");\n`);
        code.push(`RequestBody body = RequestBody.create(mediaType, `);
        code.push(JSON.stringify(data.requestBody.rawData));
        code.push('");\n');
    }

    private getPostBodyStr(rawData: string) {
        // let str = rawData.replace(/^\n\s+/g, '\n');
        let str = rawData.replace(/\"/g, '\\\"');
        str = str.replace(/\n/g, '" + \n"');
        return str;
    }
}
